#include "bernoullidirectnode.h"

BernoulliDirectNode::BernoulliDirectNode(QString label, double val, double sd, Node * parent, bool constant, bool isObserved):
    Node(label, val, sd, isObserved)
{
    holdConstant = constant;
    pNode = addParentNode(parent);
}

BernoulliDirectNode::BernoulliDirectNode(QString label, double val, double sd, bool constant, bool isObserved ) :
        Node(label, val, sd, isObserved)
{
    holdConstant = constant;
}

bool BernoulliDirectNode::inRange(double v)
{
    return 0.0 <= v || v <= 1.0;
}

void BernoulliDirectNode::setStateDistribution(int state, double distribution)
{
    // key is binary representation of state of parent nodes:
    // for instance, if this node has three parent nodes with states
    // T, T, and F, then key is binary value 110 or 6
    parentDistributions[state] = distribution;
}

double BernoulliDirectNode::generateSample()
{
    if(holdConstant || isObserved)
        return value;

    // p(me | everyone else)
    useCandidate = true;

    candidateValue = 1.0;
    double pTrue = exp(computeCompleteConditional());

    // p(!me | everyone else)
    candidateValue = 0.0;
    double pFalse = exp(computeCompleteConditional());

    useCandidate   = false;

    double p = pTrue / (pTrue + pFalse);

    return value = (double)gsl_ran_bernoulli(randomNumberGenerator, p);
}


double BernoulliDirectNode::computeLogLikelihood()
{
    // no look up table, but p is controlled by parent
    if(parentDistributions.count() == 0)
    {
        double p = parents->at(pNode)->getValue();
        if((candidateValue == 0.0 && useCandidate) || (value == 0.0 && !useCandidate))
            p = 1 - p;
        return VALID_LOG(p);
    }

    // build binary representation of state of current parents
    int state = 0;
    double p ;            

    // if I have no parents, then the two values in the map should be p, or 1 - p
    if(parents->count() == 0)
    {
        state = getValue();
        p     = parentDistributions.value(state);
    }

    // otherwise determine my state given my immediate parent(s) state(s)
    else
    {
        for(int i = 0; i < parents->count(); i++, state = state << 1)
        {
            if(parents->at(i)->getValue() != 0.0)
            {
                state |= 1;
            }
        }
        state = state >> 1;

        p     = parentDistributions.value(state);

        if(getValue() == 0.0)
            p = 1 - p;
    }

    return VALID_LOG(p);
}
